package com.polaris.live.utils.image

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.graphics.Movie
import android.graphics.drawable.AnimatedImageDrawable
import android.graphics.drawable.Drawable
import android.os.Build
import android.text.TextUtils
import android.view.ViewGroup
import com.blankj.utilcode.util.EncodeUtils
import com.blankj.utilcode.util.EncryptUtils
import com.blankj.utilcode.util.FileUtils
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
import com.luck.picture.lib.basic.PictureSelectionCameraModel
import com.luck.picture.lib.basic.PictureSelectionModel
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.polaris.live.App
import com.polaris.live.common.constant.AppConst.UpLoad.UploadType
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.engine.GlideEngine
import com.polaris.live.common.ext.dp
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.network.AppException
import com.polaris.live.common.network.HTTP_SUCCESS_CODE
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.interface_bag.S3UploadCallback
import com.polaris.live.manager.AppConfigManager
import com.polaris.live.net.userService
import com.polaris.live.resp.back_resp.UploadUrlResp
import com.polaris.live.utils.CommonUtils
import com.polaris.live.utils.image.ImageUtils.OkHttpClientSingleton.client
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import top.zibin.luban.Luban
import top.zibin.luban.OnCompressListener
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.net.URL
import java.util.concurrent.TimeUnit

/**
 * 图片上传工具类
 *
 * @author Created by 半仙 on 2023/9/4/004 15:14
 */
object ImageUtils {

    /**
     * 最大选择图片大小
     */
    const val MAX_SELECT_SIZE = 100 * 1024 * 1024L

    const val SMALL_PIC = "?width=120&height=120"
    const val MIDDLE_PIC = "?width=200&height=200"
    const val BIG_PIC = "?width=800&height=600"

    object OkHttpClientSingleton {

        val client: OkHttpClient by lazy {
            OkHttpClient.Builder()
                .connectTimeout(15, TimeUnit.SECONDS) // 设置连接超时时间
                .readTimeout(15, TimeUnit.SECONDS) // 设置读取超时时间
                .writeTimeout(15, TimeUnit.SECONDS) // 设置写入超时时间
                .build()
        }

    }

    //传头像拼接在一起
    fun imgPath(url: String?): String {
        return if (url == null) {
            ""
        } else if (isLocalPath(url)) { //本地地址
            return url
        } else if (url.startsWith("http")) {
            url
        } else {
            val prefixUrl = AppConfigManager.getConfig(CommonConst.Configs.ossUrl) ?: ""
            if (url.startsWith("/")) {
                prefixUrl + url
            } else {
                "$prefixUrl/$url"
            }
        }
    }

    //传头像拼接在一起
    fun imgPathSmall(url: String?): String {
        return if (url == null) {
            ""
        } else if (isLocalPath(url)) { //本地地址
            return url
        } else if (url.startsWith("http")) {
            url + SMALL_PIC
        } else {
            val prefixUrl = AppConfigManager.getConfig(CommonConst.Configs.ossUrl) ?: ""
            if (url.startsWith("/")) {
                prefixUrl + url + SMALL_PIC
            } else {
                "$prefixUrl/$url$SMALL_PIC"
            }
        }
    }

    //传头像拼接在一起
    fun imgPathMiddle(url: String?): String {
        return if (url == null) {
            ""
        } else if (isLocalPath(url)) { //本地地址
            return url
        } else if (url.startsWith("http")) {
            url + MIDDLE_PIC
        } else {
            val prefixUrl = AppConfigManager.getConfig(CommonConst.Configs.ossUrl) ?: ""
            if (url.startsWith("/")) {
                prefixUrl + url + MIDDLE_PIC
            } else {
                "$prefixUrl/$url$MIDDLE_PIC"
            }
        }
    }

    //传头像拼接在一起
    fun imgPathBig(url: String?): String {
        return if (url == null) {
            ""
        } else if (isLocalPath(url)) { //本地地址
            return url
        } else if (url.startsWith("http")) {
            url + BIG_PIC
        } else {
            val prefixUrl = AppConfigManager.getConfig(CommonConst.Configs.ossUrl) ?: ""
            if (url.startsWith("/")) {
                prefixUrl + url + BIG_PIC
            } else {
                "$prefixUrl/$url$BIG_PIC"
            }
        }
    }

    /**
     * 判断是否为本地地址
     */
    fun isLocalPath(path: String): Boolean {
        return path.startsWith("/storage") || path.startsWith("storage")
    }

    /**
     * S3上传bitmap
     *
     * @param bitmap 图片
     * @param type 类型
     * @param maxSize 最大尺寸
     * @param callback 回调
     */
    fun s3Upload(
        bitmap: Bitmap,
        @UploadType type: Int,
        maxSize: Int = 256,
        callback: S3UploadCallback,
    ) {
        CoroutineScopeManager.ioScope.launch {
            try {
                s3Upload(bitmap, type, maxSize).also { resp ->
                    withContext(CoroutineScopeManager.mainDispatcher) {
                        callback.onSuccess(resp.path, resp.size)
                    }
                }
            } catch (t: Throwable) {
                t.printStackTrace()

                withContext(CoroutineScopeManager.mainDispatcher) {
                    callback.onFailure(t)
                }
            }
        }
    }

    /**
     * S3上传本地文件
     *
     * @param path 本地图片路径
     * @param type 类型
     * @param maxSize 最大尺寸
     */
    fun s3Upload(
        path: String,
        @UploadType type: Int,
        maxSize: Int = 256,
        callback: S3UploadCallback,
    ) {
        CoroutineScopeManager.ioScope.launch {
            try {
                s3Upload(path, type, maxSize).also { resp ->
                    withContext(CoroutineScopeManager.mainDispatcher) {
                        callback.onSuccess(resp.path, resp.size)
                    }
                }
            } catch (t: Throwable) {
                LogExt.logE("--net", t)

                withContext(CoroutineScopeManager.mainDispatcher) {
                    callback.onFailure(t)
                }
            }
        }
    }

    /**
     * S3上传bitmap
     *
     * @param bitmap 图片
     * @param type 类型
     * @param maxSize 最大尺寸
     */
    suspend fun s3Upload(bitmap: Bitmap, @UploadType type: Int, maxSize: Int = 256): UploadUrlResp {
        return withContext(CoroutineScopeManager.ioDispatcher) {
            invokeS3Upload(bitmap, null, type, maxSize)
        }
    }

    /**
     * S3上传本地文件
     *
     * @param path 本地图片路径
     * @param type 类型
     * @param maxSize 最大尺寸
     */
    suspend fun s3Upload(path: String, @UploadType type: Int, maxSize: Int = 256): UploadUrlResp {
        return withContext(CoroutineScopeManager.ioDispatcher) {
            invokeS3Upload(null, path, type, maxSize)
        }
    }

    /**
     * 上传  上传图片的类型  不知道的去  AppConst.UpLoad里看
     */
    private suspend fun invokeS3Upload(
        bitmap: Bitmap?,
        path: String?,
        type: Int,
        maxSize: Int,
    ): UploadUrlResp {
        val fileName = CommonUtils.uuid() + "-image.jpg"

        var file: File? = null

        if (bitmap != null) {
            file = saveBitmapToFile(bitmap, fileName)
        }

        if (file == null && !path.isNullOrEmpty()) {
            val tempFile = File(path)
            if (tempFile.exists()) {
                val targetFile = File(App.instance.cacheDir, fileName)
                FileUtils.copy(tempFile, targetFile)
                file = tempFile
            } else {
                throw AppException(500, "Path does not exist")
            }
        }
        if (file == null) {
            throw AppException(500, "Bitmap and Path cannot both be empty")
        }

        val newFile = compress(file, maxSize).await()

        val encryptMD5 = EncodeUtils.base64Encode2String(EncryptUtils.encryptMD5File(newFile))

        val resp = uploadImage(
            fileName,
            type,
            FileUtils.getLength(newFile).toInt(),
            encryptMD5
        )

        uploadFile(newFile, resp.uploadUrl, encryptMD5).await()

        return resp.apply { size = BitmapUtils.readBitmapSize(newFile.path) }
    }

    /**
     * 判断是不是动态图
     */
    private fun isAnimated(file: File): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            try {
                val source = ImageDecoder.createSource(file)
                val drawable = ImageDecoder.decodeDrawable(source) { decoder, info, source ->
                    // 可以在这里进行一些配置
                }
                return drawable is AnimatedImageDrawable
            } catch (e: IOException) {
                e.printStackTrace()
                return false
            }
        } else {
            try {
                FileInputStream(file).use { inputStream ->
                    val movie = Movie.decodeStream(inputStream)
                    return movie != null
                }
            } catch (e: IOException) {
                e.printStackTrace()
                return false
            }
        }
    }

    //截图保存成文件
    private fun saveBitmapToFile(bitmap: Bitmap, fileName: String): File? {
        return try {
            File(App.instance.cacheDir, fileName).apply {
                FileOutputStream(this).use {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, it)
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
            null
        }
    }

    private fun uploadFile(
        file: File,
        url: String,
        md5: String,
    ) = CompletableDeferred<Unit>().apply {
        val body = okhttp3.RequestBody.create(null, file.readBytes())

        val request = Request.Builder()
            .url(URL(url))
            .put(body)
            .header("Content-Type", "image/jpg")
            .header("Content-MD5", md5)
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                completeExceptionally(e)
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    complete(Unit)
                } else {
                    completeExceptionally(AppException(response.code, response.message))
                }
            }
        })
    }

    private fun compress(file: File, maxSize: Int) = CompletableDeferred<File>().apply {
        val dir = App.instance.cacheDir.path + "/luban"
        FileUtils.createOrExistsDir(dir)

        Luban.with(ViewUtils.getAliveTopActivity() ?: App.instance)
            .load(file)
            .ignoreBy(maxSize)
            .setTargetDir(dir)
            .filter { !(TextUtils.isEmpty(it) || it.lowercase().endsWith(".gif")) }
            .setCompressListener(object : OnCompressListener {
                override fun onStart() {
                }

                override fun onSuccess(tempfile: File) {
                    complete(tempfile)
                }

                override fun onError(it: Throwable) {
                    completeExceptionally(it)
                }
            })
            .launch()
    }

    private suspend fun uploadImage(
        fileName: String,
        fileType: Int,
        length: Int,
        md5: String,
    ): UploadUrlResp {
        val resp = userService.uploadUrl(fileName, fileType, length, md5)
        val result = resp.result
        if (resp.code != HTTP_SUCCESS_CODE || result == null) {
            throw AppException(resp.code, resp.errorMessage)
        }
        return result
    }

    // 加载网络图片并返回 Drawable
    suspend fun loadNetImageDrawable(
        context: Context,
        url: String,
        width: Int,
        height: Int,
    ): Drawable? {
        val requestOptions = RequestOptions().override(width.dp, height.dp).transform(CircleCrop())

        if (!ViewUtils.isContextValid(context)) {
            return null
        }

        val deferred = CompletableDeferred<Drawable?>()
        Glide.with(context)
            .load(url)
            .apply(requestOptions)
            .addListener(object : RequestListener<Drawable> {
                override fun onResourceReady(
                    resource: Drawable?,
                    model: Any?,
                    target: Target<Drawable>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(resource)

                    return true
                }

                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Drawable>?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(null)
                    return true
                }
            })
            .submit() // 使用 submit 方法代替 into 方法，以便在后台线程中执行

        return deferred.await()
    }

    /**
     * 加载本地图片
     */
    suspend fun loadImage(
        context: Context,
        resId: Int?,
        width: Int? = null,
        height: Int? = null,
        needCir: Boolean = false,
    ): Drawable? {
        return loadImage(context, resId, width?.toFloat(), height?.toFloat(), needCir)
    }

    /**
     * 加载本地图片
     */
    suspend fun loadImage(
        context: Context,
        resId: Int?,
        width: Float? = null,
        height: Float? = null,
        needCir: Boolean = false,
    ): Drawable? {
        val requestOptions = RequestOptions().override(
            width?.dp?.toInt() ?: ViewGroup.LayoutParams.WRAP_CONTENT,
            height?.dp?.toInt() ?: ViewGroup.LayoutParams.WRAP_CONTENT
        )
        if (needCir) {
            requestOptions.transform(CircleCrop())
        }

        if (!ViewUtils.isContextValid(context)) {
            return null
        }

        val deferred = CompletableDeferred<Drawable?>()
        Glide.with(context)
            .load(resId)
            .apply(requestOptions)
            .addListener(object : RequestListener<Drawable> {
                override fun onResourceReady(
                    resource: Drawable?,
                    model: Any?,
                    target: Target<Drawable>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(resource)
                    return true
                }

                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Drawable>?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(null)
                    return true
                }
            })
            .submit() // 使用 submit 方法代替 into 方法，以便在后台线程中执行
        return deferred.await()
    }

    //本地源文件加载出来转成bitmap
    fun getBitmapFromDrawable(context: Context, drawableId: Int): Bitmap {
        return BitmapFactory.decodeResource(context.resources, drawableId)
    }

    // 加载网络图片并返回 Bitmap
    suspend fun loadNetImageBitmap(
        context: Context,
        url: String,
        width: Int? = null,
        height: Int? = null,
    ): Bitmap? {
        val requestOptions = RequestOptions().override(
            width?.dp ?: ViewGroup.LayoutParams.WRAP_CONTENT,
            height?.dp ?: ViewGroup.LayoutParams.WRAP_CONTENT
        ).transform(CircleCrop())

        if (!ViewUtils.isContextValid(context)) {
            return null
        }

        val deferred = CompletableDeferred<Bitmap?>()
        Glide.with(context)
            .asBitmap()
            .load(imgPath(url))
            .apply(requestOptions)
            .addListener(object : RequestListener<Bitmap> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(null)
                    return true
                }

                override fun onResourceReady(
                    resource: Bitmap?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(resource)
                    return true
                }

            })
            .submit()
        return deferred.await()
    }

    // 加载网络图片并返回 Bitmap
    suspend fun loadNetImageBitmapNoTransform(
        context: Context,
        url: String,
        width: Float? = null,
        height: Float? = null,
    ): Bitmap? {
        val requestOptions = RequestOptions().override(
            width?.dp?.toInt() ?: ViewGroup.LayoutParams.WRAP_CONTENT,
            height?.dp?.toInt() ?: ViewGroup.LayoutParams.WRAP_CONTENT
        )

        if (!ViewUtils.isContextValid(context)) {
            return null
        }

        val deferred = CompletableDeferred<Bitmap?>()
        Glide.with(context)
            .asBitmap()
            .load(imgPath(url))
            .apply(requestOptions)
            .addListener(object : RequestListener<Bitmap> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(null)
                    return true
                }

                override fun onResourceReady(
                    resource: Bitmap?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(resource)
                    return true
                }

            })
            .submit()
        return deferred.await()
    }

    //加载本地图片
    suspend fun loadImageBitmap(
        context: Context,
        resId: Int?,
        width: Int? = null,
        height: Int? = null,
        needCir: Boolean = false,
    ): Bitmap? {
        val requestOptions = RequestOptions().override(
            width?.dp ?: ViewGroup.LayoutParams.WRAP_CONTENT,
            height?.dp ?: ViewGroup.LayoutParams.WRAP_CONTENT
        )
        if (needCir) {
            requestOptions.transform(CircleCrop())
        }
        if (!ViewUtils.isContextValid(context)) {
            return null
        }

        val deferred = CompletableDeferred<Bitmap?>()
        Glide.with(context)
            .asBitmap()
            .load(resId)
            .apply(requestOptions)
            .addListener(object : RequestListener<Bitmap> {
                override fun onLoadFailed(
                    e: GlideException?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(null)
                    return true
                }

                override fun onResourceReady(
                    resource: Bitmap?,
                    model: Any?,
                    target: Target<Bitmap>?,
                    dataSource: DataSource?,
                    isFirstResource: Boolean,
                ): Boolean {
                    deferred.complete(resource)
                    return true
                }

            })
            .submit()
        return deferred.await()
    }

    /**
     * 判断大小是否为0KB
     */
    fun isBitmapEmpty(bitmap: Bitmap) = bitmap.byteCount == 0

    /**
     * 计算尺寸
     *
     * 不会超过屏幕大小
     */
    fun computeSize(
        ow: Int,
        oh: Int,
        maxWidth: Int = BitmapUtils.MAX_WIDTH,
        maxHeight: Int = BitmapUtils.MAX_HEIGHT
    ): Pair<Int, Int> {
        var w = ow
        var h = oh

        if (w > maxWidth) {
            h = ((maxWidth / w.toFloat()) * h).toInt()
            w = maxWidth
        }
        if (h > maxHeight) {
            w = ((maxHeight / h.toFloat()) * w).toInt()
            h = maxHeight
        }

        return w to h
    }
}

/**
 * 默认画廊选择配置
 */
fun PictureSelector.openGalleryDefault(maxSelectNum: Int): PictureSelectionModel {
    return openGallery(SelectMimeType.ofImage())
        .setFilterMaxFileSize(ImageUtils.MAX_SELECT_SIZE)
        .isWebp(false)
        .setMaxSelectNum(maxSelectNum)
        .setImageEngine(GlideEngine.createGlideEngine())
}

/**
 * 处理单选图片
 */
fun PictureSelectionModel.forResultSingle(action: (String) -> Unit) {
    forResult(object : OnResultCallbackListener<LocalMedia> {
        override fun onResult(result: ArrayList<LocalMedia>?) {
            result?.firstOrNull()?.realPath?.let { action(it) }
        }

        override fun onCancel() {}
    })
}

/**
 * 处理多选图片
 */
fun PictureSelectionModel.forResultList(action: (List<String>) -> Unit) {
    forResult(object : OnResultCallbackListener<LocalMedia> {
        override fun onResult(result: ArrayList<LocalMedia>?) {
            val list = result?.mapNotNull { it.realPath }
            if (!list.isNullOrEmpty()) {
                action(list)
            }
        }

        override fun onCancel() {}
    })
}

/**
 * 处理单选相片
 */
fun PictureSelectionCameraModel.forResultSingle(action: (String) -> Unit) {
    forResult(object : OnResultCallbackListener<LocalMedia> {
        override fun onResult(result: ArrayList<LocalMedia>?) {
            result?.firstOrNull()?.realPath?.let { action(it) }
        }

        override fun onCancel() {}
    })
}

/**
 * 处理多选相片
 */
fun PictureSelectionCameraModel.forResultList(action: (List<String>) -> Unit) {
    forResult(object : OnResultCallbackListener<LocalMedia> {
        override fun onResult(result: ArrayList<LocalMedia>?) {
            val list = result?.mapNotNull { it.realPath }
            if (!list.isNullOrEmpty()) {
                action(list)
            }
        }

        override fun onCancel() {}
    })
}